package com.sky.orangehireserver.modules.job_seeker.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sky.orangehireserver.common.domain.Users;
import com.sky.orangehireserver.common.service.UsersService;
import com.sky.orangehireserver.enums.ResponseCodeEnum;
import com.sky.orangehireserver.enums.UserRoleEnum;
import com.sky.orangehireserver.exception.BizException;
import com.sky.orangehireserver.modules.job_seeker.dto.SeekerLoginDTO;
import com.sky.orangehireserver.modules.job_seeker.dto.SeekerRegisterDTO;
import com.sky.orangehireserver.modules.job_seeker.dto.SeekerUpdateDTO;
import com.sky.orangehireserver.modules.job_seeker.service.SeekerAccountService;
import com.sky.orangehireserver.modules.job_seeker.vo.SeekerAccountVO;
import com.sky.orangehireserver.modules.job_seeker.vo.SeekerLoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 求职者账号管理服务实现类
 * 
 * @author sky
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SeekerAccountServiceImpl implements SeekerAccountService {

    private final UsersService usersService;
    
    // 简单的内存token存储，实际项目中应该使用Redis todo 后续改为Redis或Garnet
    private final ConcurrentHashMap<String, Long> tokenStore = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Long> tokenExpireStore = new ConcurrentHashMap<>();
    
    // Token过期时间（2小时）
    private static final long TOKEN_EXPIRE_TIME = 2 * 60 * 60 * 1000;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SeekerAccountVO register(SeekerRegisterDTO registerDTO) {
        log.info("求职者注册，邮箱：{}", registerDTO.getEmail());
        
        // 验证确认密码
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new BizException("PASSWORD_NOT_MATCH", "两次输入的密码不一致");
        }
        
        // 检查邮箱是否已存在
        LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Users::getEmail, registerDTO.getEmail());
        if (usersService.count(queryWrapper) > 0) {
            throw new BizException("EMAIL_EXISTS", "邮箱已存在");
        }
        
        // 加密密码
        String hashedPassword = BCrypt.hashpw(registerDTO.getPassword());
        
        // 创建用户实体
        Users user = Users.builder()
                .orgId(null) // 求职者不属于任何企业
                .name(registerDTO.getName())
                .email(registerDTO.getEmail())
                .passwordHash(hashedPassword)
                .role(UserRoleEnum.JOB_SEEKER.getCode())
                .status("active") // 新注册用户默认为激活状态
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();
        
        // 保存用户
        boolean saved = usersService.save(user);
        if (!saved) {
            throw new BizException(ResponseCodeEnum.SYSTEM_ERROR.getErrorCode(), "注册失败");
        }
        
        log.info("求职者注册成功，用户ID：{}", user.getId());
        return convertToVO(user);
    }

    @Override
    public SeekerLoginVO login(SeekerLoginDTO loginDTO) {
        log.info("求职者登录，邮箱：{}", loginDTO.getEmail());
        
        // 查找用户
        LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Users::getEmail, loginDTO.getEmail())
                .eq(Users::getRole, UserRoleEnum.JOB_SEEKER.getCode());
        
        Users user = usersService.getOne(queryWrapper);
        if (user == null) {
            throw new BizException("USER_NOT_FOUND", "用户不存在或邮箱错误");
        }
        
        // 检查用户状态
        if (!"active".equals(user.getStatus())) {
            throw new BizException("USER_INACTIVE", "用户账号已被禁用");
        }
        
        // 验证密码
        if (!BCrypt.checkpw(loginDTO.getPassword(), user.getPasswordHash())) {
            throw new BizException("PASSWORD_ERROR", "密码错误");
        }
        
        // 生成访问令牌
        String accessToken = generateToken(user.getId());
        
        log.info("求职者登录成功，用户ID：{}", user.getId());
        
        return SeekerLoginVO.builder()
                .accessToken(accessToken)
                .tokenType("Bearer")
                .expiresIn(TOKEN_EXPIRE_TIME / 1000)
                .userInfo(convertToVO(user))
                .build();
    }

    @Override
    public SeekerAccountVO getSeekerById(Long userId) {
        log.info("查询求职者信息，用户ID：{}", userId);
        
        Users user = usersService.getById(userId);
        if (user == null) {
            throw new BizException("USER_NOT_FOUND", "用户不存在");
        }
        
        // 检查是否为求职者
        if (!UserRoleEnum.isJobSeeker(user.getRole())) {
            throw new BizException("INVALID_USER_TYPE", "用户类型错误");
        }
        
        return convertToVO(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SeekerAccountVO updateSeeker(Long userId, SeekerUpdateDTO updateDTO) {
        log.info("更新求职者信息，用户ID：{}", userId);
        
        // 检查用户是否存在
        Users existingUser = usersService.getById(userId);
        if (existingUser == null) {
            throw new BizException("USER_NOT_FOUND", "用户不存在");
        }
        
        // 检查是否为求职者
        if (!UserRoleEnum.isJobSeeker(existingUser.getRole())) {
            throw new BizException("INVALID_USER_TYPE", "用户类型错误");
        }
        
        // 如果更新邮箱，检查新邮箱是否已被其他用户使用
        if (StrUtil.isNotBlank(updateDTO.getEmail()) && !updateDTO.getEmail().equals(existingUser.getEmail())) {
            LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Users::getEmail, updateDTO.getEmail())
                    .ne(Users::getId, userId);
            if (usersService.count(queryWrapper) > 0) {
                throw new BizException("EMAIL_EXISTS", "邮箱已存在");
            }
        }
        
        // 更新用户信息（只更新非空字段）
        Users updateUser = new Users();
        updateUser.setId(userId);
        updateUser.setUpdatedAt(LocalDateTime.now());
        
        if (StrUtil.isNotBlank(updateDTO.getName())) {
            updateUser.setName(updateDTO.getName());
        }
        if (StrUtil.isNotBlank(updateDTO.getEmail())) {
            updateUser.setEmail(updateDTO.getEmail());
        }
        if (StrUtil.isNotBlank(updateDTO.getAvatar())) {
            updateUser.setAvatar(updateDTO.getAvatar());
        }
        
        // 执行更新
        boolean updated = usersService.updateById(updateUser);
        if (!updated) {
            throw new BizException(ResponseCodeEnum.SYSTEM_ERROR.getErrorCode(), "更新用户信息失败");
        }
        
        // 返回更新后的用户信息
        Users updatedUser = usersService.getById(userId);
        log.info("求职者信息更新成功，用户ID：{}", userId);
        return convertToVO(updatedUser);
    }

    @Override
    public void logout(Long userId, String token) {
        log.info("求职者退出登录，用户ID：{}", userId);
        
        // 从token存储中移除
        tokenStore.remove(token);
        tokenExpireStore.remove(token);
        
        log.info("求职者退出登录成功，用户ID：{}", userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAccount(Long userId) {
        log.info("注销求职者账号，用户ID：{}", userId);
        
        // 检查用户是否存在
        Users user = usersService.getById(userId);
        if (user == null) {
            throw new BizException("USER_NOT_FOUND", "用户不存在");
        }
        
        // 检查是否为求职者
        if (!UserRoleEnum.isJobSeeker(user.getRole())) {
            throw new BizException("INVALID_USER_TYPE", "用户类型错误");
        }
        
        // TODO: 检查用户是否还有相关的业务数据，如投递记录、简历等
        // 这里可以根据业务需求添加相关检查逻辑
        
        // 执行删除
        boolean deleted = usersService.removeById(userId);
        if (!deleted) {
            throw new BizException(ResponseCodeEnum.SYSTEM_ERROR.getErrorCode(), "注销账号失败");
        }
        
        // 清除相关的token
        tokenStore.entrySet().removeIf(entry -> entry.getValue().equals(userId));
        
        log.info("求职者账号注销成功，用户ID：{}", userId);
    }

    @Override
    public Long validateToken(String token) {
        if (StrUtil.isBlank(token)) {
            return null;
        }
        
        // 检查token是否存在
        Long userId = tokenStore.get(token);
        if (userId == null) {
            return null;
        }
        
        // 检查token是否过期
        Long expireTime = tokenExpireStore.get(token);
        if (expireTime == null || System.currentTimeMillis() > expireTime) {
            tokenStore.remove(token);
            tokenExpireStore.remove(token);
            return null;
        }
        
        return userId;
    }

    @Override
    public SeekerLoginVO refreshToken(String token) {
        log.info("刷新访问令牌");
        
        Long userId = validateToken(token);
        if (userId == null) {
            throw new BizException("INVALID_TOKEN", "无效的访问令牌");
        }
        
        // 获取用户信息
        Users user = usersService.getById(userId);
        if (user == null || !"active".equals(user.getStatus())) {
            throw new BizException("USER_INVALID", "用户不存在或已被禁用");
        }
        
        // 移除旧token
        tokenStore.remove(token);
        tokenExpireStore.remove(token);
        
        // 生成新token
        String newAccessToken = generateToken(userId);
        
        log.info("访问令牌刷新成功，用户ID：{}", userId);
        
        return SeekerLoginVO.builder()
                .accessToken(newAccessToken)
                .tokenType("Bearer")
                .expiresIn(TOKEN_EXPIRE_TIME / 1000)
                .userInfo(convertToVO(user))
                .build();
    }

    /**
     * 生成访问令牌
     * 
     * @param userId 用户ID
     * @return 访问令牌
     */
    private String generateToken(Long userId) {
        String token = UUID.randomUUID().toString().replace("-", "");
        long expireTime = System.currentTimeMillis() + TOKEN_EXPIRE_TIME;
        
        tokenStore.put(token, userId);
        tokenExpireStore.put(token, expireTime);
        
        return token;
    }

    /**
     * 将Users实体转换为SeekerAccountVO
     * 
     * @param user 用户实体
     * @return 求职者账号VO
     */
    private SeekerAccountVO convertToVO(Users user) {
        SeekerAccountVO vo = BeanUtil.copyProperties(user, SeekerAccountVO.class);
        
        // 设置角色名称
        UserRoleEnum roleEnum = UserRoleEnum.getByCode(user.getRole());
        if (roleEnum != null) {
            vo.setRoleName(roleEnum.getName());
        }
        
        return vo;
    }
}